// tipsy, facebook style tooltips for jquery
// version 1.0.0a
// (c) 2008-2010 jason frame [jason@onehackoranother.com]
// releated under the MIT license

(function($){
    function fixTitle($ele){
        if($ele.attr('title')||typeof($ele.attr('original-title'))!='string'){
            $ele.attr('original-title',$ele.attr('title')||'').removeAttr('title');
        }
    }
    function Tipsy(element,options){
    this.$element=$(element);
    this.options=options;
    this.enabled=true;
    fixTitle(this.$element);
}
Tipsy.prototype={
    show:function(){
        var title=this.getTitle();
        if(title&&this.enabled){
            var $tip=this.tip();
            $tip.find('.tipsy-inner')[this.options.html?'html':'text'](title);
            $tip[0].className='tipsy';
            $tip.remove().css({
                top:0,
                left:0,
                visibility:'hidden',
                display:'block'
            }).appendTo(document.body);
            var pos=$.extend({},this.$element.offset(),{
                width:this.$element[0].offsetWidth,
                height:this.$element[0].offsetHeight
                });
            var actualWidth=$tip[0].offsetWidth,actualHeight=$tip[0].offsetHeight;
            var gravity=(typeof this.options.gravity=='function')?this.options.gravity.call(this.$element[0]):this.options.gravity;
            var tp;
            switch(gravity.charAt(0)){
                case'n':
                    tp={
                    top:pos.top+pos.height+this.options.offset,
                    left:pos.left+pos.width/2-actualWidth/2
                    };
                    
                break;
                case's':
                    tp={
                    top:pos.top-actualHeight-this.options.offset,
                    left:pos.left+pos.width/2-actualWidth/2
                    };
                    
                break;
                case'e':
                    tp={
                    top:pos.top+pos.height/2-actualHeight/2,
                    left:pos.left-actualWidth-this.options.offset
                    };
                    
                break;
                case'w':
                    tp={
                    top:pos.top+pos.height/2-actualHeight/2,
                    left:pos.left+pos.width+this.options.offset
                    };
                    
                break;
            }
            if(gravity.length==2){
                if(gravity.charAt(1)=='w'){
                    tp.left=pos.left+pos.width/2-15;
                }else{
                    tp.left=pos.left+pos.width/2-actualWidth+15;
                }
            }
            $tip.css(tp).addClass('tipsy-'+gravity);
        if(this.options.fade){
            $tip.stop().css({
                opacity:0,
                display:'block',
                visibility:'visible'
            }).animate({
                opacity:this.options.opacity
                });
        }else{
            $tip.css({
                visibility:'visible',
                opacity:this.options.opacity
                });
        }
    }
},
hide:function(){
    if(this.options.fade){
        this.tip().stop().fadeOut(function(){
            $(this).remove();
        });
    }else{
        this.tip().remove();
    }
},
getTitle:function(){
    var title,$e=this.$element,o=this.options;
    fixTitle($e);
    var title,o=this.options;
    if(typeof o.title=='string'){
        title=$e.attr(o.title=='title'?'original-title':o.title);
    }else if(typeof o.title=='function'){
        title=o.title.call($e[0]);
    }
    title=(''+title).replace(/(^\s*|\s*$)/,"");
    return title||o.fallback;
},
tip:function(){
    if(!this.$tip){
        this.$tip=$('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><b class="xtop"><b class="xb1"></b><b class="xb2"></b><b class="xb3"></b><b class="xb4"></b></b><div class="tipsy-inner"/></div><b class="xbottom"><b class="xb4"></b><b class="xb3"></b><b class="xb2"></b><b class="xb1"></b></b>');
    }
    return this.$tip;
},
validate:function(){
    if(!this.$element[0].parentNode){
        this.hide();
        this.$element=null;
        this.options=null;
    }
},
enable:function(){
    this.enabled=true;
},
disable:function(){
    this.enabled=false;
},
toggleEnabled:function(){
    this.enabled=!this.enabled;
}
};

$.fn.tipsy=function(options){
    if(options===true){
        return this.data('tipsy');
    }else if(typeof options=='string'){
        return this.data('tipsy')[options]();
    }
    options=$.extend({},$.fn.tipsy.defaults,options);
    function get(ele){
        var tipsy=$.data(ele,'tipsy');
        if(!tipsy){
            tipsy=new Tipsy(ele,$.fn.tipsy.elementOptions(ele,options));
            $.data(ele,'tipsy',tipsy);
        }
        return tipsy;
    }
    function enter(){
        var tipsy=get(this);
        tipsy.hoverState='in';
        if(options.delayIn==0){
            tipsy.show();
        }else{
            setTimeout(function(){
                if(tipsy.hoverState=='in')tipsy.show();
            },options.delayIn);
        }
    };
    
function leave(){
    var tipsy=get(this);
    tipsy.hoverState='out';
    if(options.delayOut==0){
        tipsy.hide();
    }else{
        setTimeout(function(){
            if(tipsy.hoverState=='out')tipsy.hide();
        },options.delayOut);
    }
};

if(!options.live)this.each(function(){
    get(this);
});
if(options.trigger!='manual'){
    var binder=options.live?'live':'bind',eventIn=options.trigger=='hover'?'mouseenter':'focus',eventOut=options.trigger=='hover'?'mouseleave':'blur';
    this[binder](eventIn,enter)[binder](eventOut,leave);
}
return this;
};

$.fn.tipsy.defaults={
    delayIn:0,
    delayOut:0,
    fade:false,
    fallback:'',
    gravity:'n',
    html:false,
    live:false,
    offset:0,
    opacity:0.8,
    title:'title',
    trigger:'hover'
};

$.fn.tipsy.elementOptions=function(ele,options){
    return $.metadata?$.extend({},options,$(ele).metadata()):options;
};

$.fn.tipsy.autoNS=function(){
    return $(this).offset().top>($(document).scrollTop()+$(window).height()/2)?'s':'n';
};

$.fn.tipsy.autoWE=function(){
    return $(this).offset().left>($(document).scrollLeft()+$(window).width()/2)?'e':'w';
};

})(jQuery);